package com.jack.wlbletest;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.Manifest;
import android.bluetooth.BluetoothDevice;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.ScrollingMovementMethod;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.View;

import com.jack.wlbletest.databinding.ActivityMainBinding;
import com.vois.jack.btmgr.blebase.BleConstant;
import com.vois.jack.btmgr.blebase.BleDevCommonMsg;
import com.vois.jack.btmgr.blebase.BleDevMgr;
import com.vois.jack.btmgr.blebase.BleDevice;
import com.vois.jack.btmgr.blebase.BleDeviceBuilder;
import com.vois.jack.btmgr.blebase.BleScanResult;
import com.vois.jack.btmgr.classicbase.BtDevCommonMsg;
import com.vois.jack.btmgr.classicbase.BtDevConstant;
import com.vois.jack.btmgr.classicbase.BtDevMgr;
import com.vois.jack.btmgr.classicbase.BtDevice;
import com.vois.jack.btmgr.classicbase.BtDeviceBuilder;
import com.vois.jack.btmgr.classicbase.BtErrorCode;
import com.vois.jack.btmgr.classicbase.BtRecorderInterface;
import com.vois.jack.btmgr.common.DeviceRecorderControlInterface;
import com.vois.jack.btmgr.devices.WLBleBtnDevice.WLBleBtnDevice;
import com.vois.jack.btmgr.devices.WLBleOpusDevice.WLBleOpusDevice;
import com.vois.jack.btmgr.devices.WLBtOpusDevice.WLBtOpusDevice;
import com.vois.jack.btmgr.devices.WLSideKeyDevice.WLSideKeyDevice;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getName();
    private static final int FIND_BLE_DEV = 88;
    private static final int FIND_BATCH_BLE_DEV = 923;
    private static final int SCAN_STARTED = 72;
    private static final int READ_DATA = 986;
    private static final int DEBUG_INFO = 449;
    private static final int DEVICE_CONNECTED = 803;
    private static final int DEVICE_DISCONNECTED = 40;
    private static final int DEVIEC_READY = 897;
    private ActivityMainBinding binding;
    private BleAdapter adapter;
    private BleDevMgr bleDevMgr;
    private BtDevMgr btDevMgr;
    private boolean isScanning;
    private boolean isConnecting;
    private boolean isConnected;
    private ArrayList<BluetoothDevice> bleList;
    private LocalHandle handle;
    private BleDevice curDevice;
    private BtRecorderInterface recorderInterface;
    private int infoSize = 0;
    private Timer readData;
    private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
            'E', 'F'};

    private String dump_data(byte[] data, int dataSize) {
        StringBuffer stringBuffer = new StringBuffer();
        char[] out = new char[dataSize * 3];
        try {
            for (int i = 0, j = 0; i < dataSize; i++) {
                out[j++] = DIGITS_UPPER[(0xF0 & data[i]) >>> 4];
                out[j++] = DIGITS_UPPER[0x0F & data[i]];
                out[j++] = ',';
            }

            stringBuffer.append("[" + dataSize + "]:\n");
            stringBuffer.append(out);
            stringBuffer.append("\n");
            stringBuffer.append("------------------------\n");
            Log.d(TAG, "dump_data: " + stringBuffer);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "dumpArray error: " + e.getMessage());
            stringBuffer.append(e.getMessage());
        }

        return stringBuffer.toString();
    }

    class LocalHandle extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case FIND_BLE_DEV: {
                    adapter.addItem((BluetoothDevice) msg.obj);
                }
                break;

                case FIND_BATCH_BLE_DEV: {
                    if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                        BleScanResult[] scanResults = (BleScanResult[]) msg.obj;
                        for (BleScanResult result : scanResults) {
                            adapter.addItem(result.getBluetoothDevice());
                        }
                    }
                }
                break;

                case DEVICE_DISCONNECTED: {
                    isConnected = false;
                    isConnecting = false;
                    isScanning = false;
                    binding.btnScan.setText("Scan");
                    binding.btnScan.setEnabled(true);

                    binding.recyclerView.setVisibility(View.VISIBLE);
                    binding.btnpanel.setVisibility(View.INVISIBLE);
                }
                break;

                case DEVICE_CONNECTED: {
                    isConnected = true;
                    isConnecting = false;
                    isScanning = false;
                    binding.btnScan.setText("Disconnect");
                    binding.btnScan.setEnabled(true);

                    if (binding.recyclerView.getChildCount() > 0) {
                        binding.recyclerView.removeAllViews();
                        adapter.clearData();
                    }
                }
                break;

                case DEBUG_INFO: {
                    binding.editTextTextMultiLine.setMovementMethod(ScrollingMovementMethod.getInstance());
                    binding.editTextTextMultiLine.setSelection(binding.editTextTextMultiLine.getText().length(), binding.editTextTextMultiLine.getText().length());
                    binding.editTextTextMultiLine.append((String) msg.obj);
                    binding.editTextTextMultiLine.append("\n");

                    infoSize = binding.editTextTextMultiLine.getText().length();

                    if (infoSize > 8090) {
                        binding.editTextTextMultiLine.setText("");
                        infoSize = 0;
                    }


                }
                break;

                case READ_DATA: {
                    byte[] data = new byte[1024];
                    Log.d(TAG, "handleMessage: get recorder data");
                    if (recorderInterface != null) {
                        int len = 0;
                        len = recorderInterface.getEncodedRecordData(data);
                        showInfo(dump_data(data, len));
                    }
                }
                break;

                case SCAN_STARTED: {
                    binding.recyclerView.setVisibility(View.VISIBLE);
                }
                break;

                case DEVIEC_READY: {
                    binding.recyclerView.setVisibility(View.INVISIBLE);
                    binding.btnpanel.setVisibility(View.VISIBLE);
                    curDevice = bleDevMgr.getBleDevice((BluetoothDevice) msg.obj);
                    if (curDevice.hasRecorder()) {
                        WLBleOpusDevice opusDevice = (WLBleOpusDevice)curDevice;
                        recorderInterface = opusDevice.getRecorder(DeviceRecorderControlInterface.OPUS_RECORDER);
                    }
                }
                break;
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        View view = binding.getRoot();
        setContentView(view);
        handle = new LocalHandle();

        if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
            showInfo("你没有蓝牙权限，申请中，请授权");
            requestPermissions(new String[]{
                    "android.permission.BLUETOOTH_CONNECT",
                    "android.permission.ACCESS_FINE_LOCATION",
                    "android.permission.ACCESS_COARSE_LOCATION",
                    "android.permission.BLUETOOTH",
                    "android.permission.BLUETOOTH_SCAN",
                    "android.permission.BLUETOOTH_ADMIN"}, 1);
        }

        BleDeviceBuilder.registerBleDeviceClass("VC-SK.*", WLBleBtnDevice.class, 0xB4, true);
        BleDeviceBuilder.registerBleDeviceClass("L5-B*", WLBleOpusDevice.class, 0xE4, true);
        BleDeviceBuilder.registerBleDeviceClass("BPTT*", WLBleBtnDevice.class, 0xE4, true);

        BtDeviceBuilder.registerBtDeviceClass("C1-S*", WLBtOpusDevice.class, 1);
        BtDeviceBuilder.registerBtDeviceClass("JYS*", WLBtOpusDevice.class, 1);


        adapter = new BleAdapter();
        binding.txVersiopn.setText(BuildConfig.BUILD_TYPE + "_" + BuildConfig.VERSION_NAME);
        binding.recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        binding.recyclerView.setAdapter(adapter);
        adapter.setListener(new BleAdapter.BleAdapterClickListener() {
            @Override
            public void onItemClick(int index) {
                String name;
                BluetoothDevice device = adapter.getItem(index);

                try {
                    name = device.getName();
                } catch (SecurityException e) {
                    e.printStackTrace();
                    name = "empty";
                }
                isConnecting = true;
                binding.btnScan.setEnabled(false);
                binding.btnScan.setText("connecting");
                bleDevMgr.stopScanBleDevice();
                bleDevMgr.openBleDevice(adapter.getItem(index), name, null, new BleDevice.BleDeviceListener() {
                    @Override
                    public void onConnecting(BluetoothDevice device) {
                        showInfo("ble is connecting......");
                    }

                    @Override
                    public void onConnected(BluetoothDevice device) {
                        showInfo("ble is connected");
                        handle.sendEmptyMessage(DEVICE_CONNECTED);
                    }

                    @Override
                    public void onDisconnected(BluetoothDevice device) {
                        showInfo("ble is disconnected");
                    }

                    @Override
                    public void onMessage(BluetoothDevice device, Message msg) {
                        showInfo("ble got message:" + Integer.toHexString(msg.what));
                        BleDevCommonMsg bleDevCommonMsg = BleDevCommonMsg.valueOf(msg.what);
                        try {
                            if (device != null) {
                                if (device.getName() != null) {
                                    showInfo("onMessage: " + device.getName() + " msg:" + bleDevCommonMsg);
                                } else {
                                    showInfo("onMessage: " + device.getAddress() + " msg:" + bleDevCommonMsg);
                                }
                            }
                        } catch (SecurityException e) {
                            e.printStackTrace();
                        }

                        if (bleDevCommonMsg.equals(BleDevCommonMsg.BLE_DEV_COMMON_VALIDATION_RESULT)) {
                            Bundle bundle = msg.getData();
                            String seqUUID = bundle.getString(BleConstant.EXTRA_SEQID, "");
                            showInfo(String.format("authentication#seqUUID: %s ", seqUUID));
                        } else if (bleDevCommonMsg.equals(BleDevCommonMsg.BLE_DEV_COMMON_KEY_PRESSED_MSG)) {
                            Bundle bundle = msg.getData();
                            int keyCode = bundle.getInt(BleConstant.EXTRA_KEY_CODE);
                            showInfo("Key is pressed " + Integer.toHexString(keyCode));

                            if (keyCode == 1 && curDevice.hasRecorder()) {
                                WLBleOpusDevice opusDevice = (WLBleOpusDevice)curDevice;
                                opusDevice.startRecorder(new DeviceRecorderControlInterface.ResultCallback() {
                                    @Override
                                    public void onResult(boolean result) {
                                        showInfo("start recorder result " + result);
                                        readData = new Timer();
                                        readData.schedule(new TimerTask() {
                                            @Override
                                            public void run() {
                                                handle.sendEmptyMessage(READ_DATA);
                                            }
                                        }, 300, 100);
                                        recorderInterface.startRecord();
                                    }
                                });
                            }
                        } else if (bleDevCommonMsg.equals(BleDevCommonMsg.BLE_DEV_COMMON_KEY_RELEASED_MSG)) {
                            Bundle bundle = msg.getData();
                            int keyCode = bundle.getInt(BleConstant.EXTRA_KEY_CODE);
                            showInfo("Key is release " + Integer.toHexString(keyCode));
                            if (keyCode == 1 && curDevice.hasRecorder()) {
                                WLBleOpusDevice opusDevice = (WLBleOpusDevice)curDevice;
                                opusDevice.stopRecorder(new DeviceRecorderControlInterface.ResultCallback() {
                                    @Override
                                    public void onResult(boolean result) {
                                        showInfo("stop recorder result " + result);
                                        recorderInterface.stopRecord();
                                        readData.cancel();
                                        readData = null;
                                    }
                                });
                            }
                        }

                    }

                    @Override
                    public void onClosed(BluetoothDevice device) {
                        showInfo("ble is closed");
                        handle.sendEmptyMessage(DEVICE_DISCONNECTED);
                    }

                    @Override
                    public void onError(BluetoothDevice device, int errorCause) {
                        showInfo("ble is error:" + errorCause);
                    }

                    @Override
                    public void onReady(BluetoothDevice device) {
                        showInfo("ble is ready.....");
                        handle.sendMessage(handle.obtainMessage(DEVIEC_READY, device));
                    }

                    @Override
                    public void onRssi(BluetoothDevice device, int rssi) {

                    }
                });
            }
        });

        bleDevMgr = new BleDevMgr(this, new BleDevMgr.BleMgrCallback() {
            @Override
            public void onStarted() {
                showInfo("ble manager started");
            }

            @Override
            public void onStopped() {
                showInfo("ble manager stopped");
            }

            @Override
            public void onBluetoothOn() {
                showInfo("bluetooth on");
            }

            @Override
            public void onBluetoothOff() {
                showInfo("bluetooth off");
            }
        });

        bleDevMgr.startBleManager();
        btDevMgr = new BtDevMgr();
        btDevMgr.init(this);
        btDevMgr.setListener(new BtDevMgr.BtDevListener() {
            @Override
            public void onBtMgrStarted() {
                showInfo("蓝牙设备管理已打开...");
            }

            @Override
            public void onOpenningBtDevice(BtDevice btDevice) {
                showInfo("蓝牙设备已连接..." + btDevice.getMac() + ":" + btDevice.getDeviceType());
            }

            @Override
            public void onBtMgrStopped() {
                showInfo("蓝牙设备管理已关闭...");
            }
        });
        btDevMgr.setCommonDeviceListener(new BtDevice.BtDeviceListener() {
            @Override
            public void onInited(BtDevice device) {
                showInfo(device.getProtocolName() + ": 初始化");
            }

            @Override
            public void onConnectStateChanged(BtDevice device, int profile, int state) {
                showInfo(device.getProtocolName() + ": 连接状态:" + state);
            }

            @Override
            public void onSppStateChanged(BtDevice device, int status) {
                showInfo(device.getProtocolName() + ": SPP连接状态:" + status);
                if (status == BtDevice.SPP_CONNECTED) {
                    device.getVersion();
                    device.getValidateData();
                }
            }

            @Override
            public void onScoStateChanged(BtDevice device, int state) {
                showInfo(device.getProtocolName() + ":SCO 连接状态:" + state);
            }

            @Override
            public void onMessage(BtDevice device, Message message) {
                BtDevCommonMsg btDevCommonMsg = BtDevCommonMsg.valueOf(message.what);
                showInfo( "onMessage: " + btDevCommonMsg + " message.what:" + message.what);

                if (btDevCommonMsg != BtDevCommonMsg.BT_DEV_COMMON_NONE) {
                    switch (btDevCommonMsg) {
                        case BT_DEV_COMMON_KEY_PRESSED: {
                            Bundle bundle = message.getData();
                            int keyCode = bundle.getInt("bt key code");
                            showInfo("按键按下:" + keyCode);

                            if (keyCode == 1) {
                                WLBtOpusDevice opusDevice = (WLBtOpusDevice) device;
                                opusDevice.startRecorder(new DeviceRecorderControlInterface.ResultCallback() {
                                    @Override
                                    public void onResult(boolean result) {
                                        showInfo("开启录音结果:" + result);
                                    }
                                });
                            }
                        }
                        break;

                        case BT_DEV_COMMON_KEY_RELEASED: {
                            Bundle bundle = message.getData();
                            int keyCode = bundle.getInt("bt key code");
                            showInfo("按键释放:" + keyCode);

                            if (keyCode == 1) {
                                WLBtOpusDevice opusDevice = (WLBtOpusDevice) device;
                                opusDevice.stopRecorder(new DeviceRecorderControlInterface.ResultCallback() {
                                    @Override
                                    public void onResult(boolean result) {
                                        showInfo("关闭录音结果:" + result);
                                    }
                                });
                            }
                        }
                        break;

                        case BT_DEV_COMMON_KEY_CLICKED: {
                            Bundle bundle = message.getData();
                            int keyCode = bundle.getInt("bt key code");
                            showInfo( "按键按下: " + keyCode);
                        }
                        break;

                        case BT_DEV_COMMON_READY_IND: {
                            showInfo("SPP已经连接成功");
                        }
                        break;

                        case BT_DEV_GET_VALIDATE_DATA_RET: {
                            Bundle bundle = message.getData();
                            String seqUUID = bundle.getString(BtDevConstant.EXTRA_SEQID);
                            showInfo("获得验证码:" + seqUUID);
                        }
                        break;

                        case BT_DEV_GET_VERSION_RET: {
                            Bundle bundle = message.getData();
                            String btDeviceVer;
                            btDeviceVer = bundle.getString(BtDevConstant.EXTRA_VERSION);
                            showInfo("BT_DEV_GET_VERSION_RET, ver: " + btDeviceVer);
                        }
                        break;
                    }
                }
            }

            @Override
            public void onClosed(BtDevice device) {
                showInfo(device.getProtocolName() + ":关闭:");
            }

            @Override
            public void onError(BtDevice device, int type, BtErrorCode code) {
                showInfo(device.getProtocolName() + ":遇到错误:" + code);
            }
        });

        isConnected = false;
        isConnecting = false;
        isScanning = false;
        bleList = new ArrayList<BluetoothDevice>();
        binding.btnScan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isConnecting) {
                    return;
                }

                if (isConnected) {
                    binding.btnScan.setEnabled(false);
                    curDevice.closeBleDevice();
                    return;
                }

                if (isScanning) {
                    binding.btnScan.setText("scan");
                    if (binding.recyclerView.getChildCount() > 0) {
                        binding.recyclerView.removeAllViews();
                        adapter.clearData();
                    }
                    bleDevMgr.stopScanBleDevice();
                } else {
                    binding.btnScan.setText("stop scan");
                    bleDevMgr.startScanBleDevice(null, null, 30000, new BleDevMgr.BleScanCallback() {
                        @Override
                        public void onStarting() {
                            showInfo("start scanning.....");
                            isScanning = true;
                            handle.sendEmptyMessage(SCAN_STARTED);
                        }

                        @Override
                        public void onScanFound(BluetoothDevice device, String name, byte[] rawScanData, int rssi) {
                            Message message = Message.obtain();
                            message.what = FIND_BLE_DEV;
                            message.obj = device;
                            handle.sendMessage(message);
                        }

                        @Override
                        public void onBatchScanResultFound(BleScanResult[] scanResults) {
                            Message message = Message.obtain();
                            message.what = FIND_BATCH_BLE_DEV;
                            message.obj = scanResults;
                            handle.sendMessage(message);
                        }

                        @Override
                        public void onScanFail() {
                            showInfo("scan fail.....");
                            isScanning = false;
                        }

                        @Override
                        public void onScanStopped() {
                            showInfo("scan stopped.....");
                            isScanning = false;
                        }

                        @Override
                        public void onScanTimeout() {
                            showInfo("scan timeout.......");
                            isScanning = false;
                        }
                    });
                }
            }
        });

        binding.btnPtt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (curDevice != null) {
                    curDevice.getValidationData();
                }
            }
        });
    }

    protected void showInfo(String info) {
        handle.sendMessage(handle.obtainMessage(DEBUG_INFO, info + "\n"));
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}